package BuyerAgent;

import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.core.Agent;
import jade.core.Location;
import jade.domain.FIPANames;
import jade.domain.mobility.MobilityOntology;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JTable;

import Ontologies.FruitTreeNurserySystemOntology;
import Ontologies.FruitTreeVocabulary;
import Ontologies.TreeWithPrice;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;

/**
 * This is the class for buyer agent. <br>
 * This class contains most of the necessary resources that are required for the
 * buyer agent to execute itself. <br>
 * The maximum time to make attempts to buy trees and the interval time between
 * two attempts can be adjusted through two constants MAX_NUM_TRY_TO_BUY and
 * INTERVAL_BETWEEN_ATTEMPTS
 * 
 * @author DUY HAN PHAN
 * 
 */
public class Buyer extends Agent implements FruitTreeVocabulary {

	public volatile ArrayList<Tree> wishList;
	// TODO st to save the report purchase
	public volatile StringBuilder purchaseReport = new StringBuilder("^0^~~~*0*~~~^0^  PURCHASING REPORT  ^0^~~~*0*~~~^0^\n");

	public volatile int numTryToBuy = 0;
	public final int MAX_NUM_TRY_TO_BUY = 5; // TODO try to put these in
												// BuyTreesBehaviour later
	public final long INTERVAL_BETWEEN_ATTEMPTS = 5 * 1000;// 5 seconds
	public volatile Location homeLocationOfBuyerAgent;
	public volatile Location mainContainerLocation;
	public volatile PurchaseTransactionBehaviour purchaseTransactionBehaviour;
	public volatile BuyerGUI buyerGUI;
	public volatile String agentName;
	public volatile String agentLocalName;
	public volatile Codec codec = new SLCodec();
	public volatile Ontology ontology = FruitTreeNurserySystemOntology.getInstance();
	public final List<TreeWithPrice> allTreesList = ((FruitTreeNurserySystemOntology) ontology).getAllTreesList();

	/*
	 * (non-Javadoc)
	 * 
	 * @see jade.core.Agent#setup()
	 */
	@Override
	protected void setup() {
		super.setup();

		this.agentName = this.getName();
		this.agentLocalName = this.getLocalName();

		// register the SL0 content language
		getContentManager().registerLanguage(new SLCodec(), FIPANames.ContentLanguage.FIPA_SL0);
		// register the mobility ontology
		getContentManager().registerOntology(MobilityOntology.getInstance());

		// Register language and ontology
		getContentManager().registerLanguage(codec);
		getContentManager().registerOntology(ontology);

		// TODO load the wish list from file, if the file does not exist, create
		// it (filename = WishList[agentLocalName].json)
		wishList = new ArrayList<>();
		Gson gson = new Gson();
		File wishListFile = new File("data/buyers/WishList" + agentLocalName + ".json");
		if (wishListFile.exists()) {
			BufferedReader br;
			try {
				br = new BufferedReader(new FileReader(wishListFile));
				String line;
				StringBuilder strBuilder = new StringBuilder();
				while ((line = br.readLine()) != null) {
					strBuilder.append(line);
				}
				String json = strBuilder.toString();// .replaceAll("[\\s]+",
													// "");
				JsonParser parser = new JsonParser();
				JsonArray array = parser.parse(json).getAsJsonArray();
				for (int i = 0; i < array.size(); i++) {
					Tree tree = gson.fromJson(array.get(i), Tree.class);
					wishList.add(tree);
				}
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			BufferedWriter bw;
			try {
				bw = new BufferedWriter(new FileWriter(wishListFile));
				String json = gson.toJson(wishList);
				bw.write(json);
				bw.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		// TODO show the GUI
		buyerGUI = new BuyerGUI(this);
		buyerGUI.setVisible(true);

		// TODO show wish list table
		WishListModelTable wishListModelTable = new WishListModelTable(wishList);
		JTable table = buyerGUI.table;
		table.setModel(wishListModelTable);

		// Store the original of buyer agent, so it can come back after
		// finishing the tasks
		this.homeLocationOfBuyerAgent = this.here();
		purchaseTransactionBehaviour = new PurchaseTransactionBehaviour(this);
	}

	/**
	 * Start the composite transaction behavior
	 */
	public void startPurchaseTransactionBehaviour() {
		this.addBehaviour(purchaseTransactionBehaviour);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see jade.core.Agent#beforeMove()
	 */
	@Override
	protected void beforeMove() {
		super.beforeMove();
		// TODO close the GUI
		buyerGUI.dispose();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see jade.core.Agent#afterMove()
	 */
	@Override
	protected void afterMove() {
		super.afterMove();
		if (this.here().equals(homeLocationOfBuyerAgent)) {
			System.out.println("I've just come home from main container. Let's show the result");
			// TODO show the result
			ReportGUI reportPurchaseTransactionGUI = new ReportGUI(this);
			reportPurchaseTransactionGUI.setVisible(true);
			reportPurchaseTransactionGUI.setVisible(true);
			reportPurchaseTransactionGUI.txtReport.setText(purchaseReport.toString());
			// TODO write down report to file
			saveReportToFile();
			// TODO write down new wish list to file
			saveWishListToFile();
		} else if (this.here().equals(mainContainerLocation)) {
			System.out.println("I've just arrived at main container. It's time for shopping!");
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see jade.core.Agent#takeDown()
	 */
	@Override
	protected void takeDown() {
		super.takeDown();
	}

	/**
	 * save report to text file (filename =
	 * data\buyers\Report[agentLocalName].txt)
	 */
	public void saveReportToFile() {
		File reportFile = new File("data/buyers/Report" + agentLocalName + ".txt");
		if (reportFile.exists()) {
			BufferedWriter bw;
			try {
				bw = new BufferedWriter(new FileWriter(reportFile, false));
				bw.write(purchaseReport.toString());
				bw.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			BufferedWriter bw;
			try {
				bw = new BufferedWriter(new FileWriter(reportFile));
				bw.write(purchaseReport.toString());
				bw.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * Save wish list to JSON file (filename =
	 * data\buyers\WishList[agentLocalName].json)
	 */
	public void saveWishListToFile() {
		// TODO save wish list to file, if the file exists, overwrite it
		// (filename = WishList[agentLocalName].json)
		Gson gson = new Gson();
		File wishListFile = new File("data/buyers/WishList" + agentLocalName + ".json");
		if (wishListFile.exists()) {
			BufferedWriter bw;
			try {
				bw = new BufferedWriter(new FileWriter(wishListFile, false));
				String json = gson.toJson(wishList);
				bw.write(json);
				bw.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			BufferedWriter bw;
			try {
				bw = new BufferedWriter(new FileWriter(wishListFile));
				String json = gson.toJson(wishList);
				bw.write(json);
				bw.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
